﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace SharpHomeEngine
{
    public delegate void CompletedStateChangeAsyncDelegate(Int64 Handle);

    public abstract class DeviceInterface : IChangeSource
    {
        private string MyName;
        
        /// <summary>
        /// Interface type name, set this in the constructor
        /// </summary>
        protected string InterfaceType = "BaseDeviceInterface";
        
        internal StateEngine StateEngine;

        /// <summary>
        /// Holds all the device the device interface will communicate with. Assists quick lookup by address.
        /// </summary>
        protected Dictionary<String, Device> DeviceDictionary = new Dictionary<string, Device>();


        /// <summary>
        /// Holds all the tags for all the devices that the device interface will communicate with. Assist quick lookup by address.
        /// </summary>
        protected Dictionary<String, Tag> TagDictionary = new Dictionary<string, Tag>();

        /// <summary>
        /// returns the base type of all of this interfaces devices
        /// </summary>
        protected abstract Type DeviceType { get; }

        /// <summary>
        /// the name of this instance of the device interface
        /// </summary>
        public String Name { get { return MyName; } }


        public DeviceInterface(StateEngine StateEngine, String Name)
        {
            this.StateEngine = StateEngine;
            MyName = Name;
        }

        /// <summary>
        /// All requests no matter the type get routed here
        /// </summary>
        /// <param name="Request"></param>
        public abstract void BeginRequest(Request4DeviceInterface Request);



        //public abstract void Init();
        public abstract void Start();

        /// <summary>
        /// To be called by the device interface when a unsolicited state change is detected
        /// </summary>
        /// <param name="Device"></param>
        /// <param name="Tag"></param>
        /// <param name="Value"></param>
        protected void UnsolicitedTagStateChange(Device Device, Tag Tag, object Value)
        {
            if (Tag.ValueObj != Value) //only fire if its a change.
            {
                Tag.SetValue(Value);
                StateEngine.RaiseChangeTagState(this, Device, Tag, Value);
            }
        }

        /// <summary>
        /// Called by the device interface to register each tag it will be dealing with often by the init fucntion
        /// </summary>
        /// <param name="Tag"></param>
        protected void RegisterTag(Tag Tag){
            if (TagDictionary.ContainsKey(Tag.Address))
            {
                throw new Exception("Tag already registered");
            }
            StateEngine.RegisterTag(Tag);
            TagDictionary.Add(Tag.Address, Tag);
        }

        /// <summary>
        /// Called by external controllers and configurators to register a device.
        /// </summary>
        /// <param name="Device"></param>
        public virtual void RegisterDevice(Device Device)
        {
            if (Device == null)
            {
                throw new Exception("Device cannot be null");
            }
            if (DeviceDictionary.ContainsKey(Device.Address))
            {
                throw new Exception("this device is already registered");
            }

            Type Type = Device.GetType();
            if (!Type.IsSubclassOf(DeviceType))
            {
                throw new Exception("Not the right kind of device");
            }            
            
            DeviceDictionary.Add(Device.Address, Device);
        }

        /// <summary>
        /// Asks the devices for their lists of tags and registers tem.
        /// This can be overridden to accomdate any other initialization routines of the DeviceInterface
        /// </summary>
        public virtual void Init()
        {
            foreach (Device Device in DeviceDictionary.Values)
            {
                List<Tag> Tags = Device.GetTags();
                foreach (Tag Tag in Tags)
                {
                    RegisterTag(Tag);
                }
            }
        }


    }
}
